home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 3 / Your Choice Software Collection 3.iso / prgmming / swag05 / network.swg < prev    next >
Text File  |  1994-09-22  |  112KB  |  1 lines

  1. SWAGOLX.EXE (c) 1993 GDSOFT  ALL RIGHTS RESERVED 00003                                                                           1      05-25-9408:22ALL                      JIM ROBB                 Re: Get Server Date      SWAG9405            14     ,î   {π MP> Can someone show me what a PASCAL procedure would look like toπ MP> encapsulate the following information (from Brown's int list):π MP> INT 21 - Novell NetWare - FILE SERVER - GET FILE SERVER DATE AND TIMEππI tested this on our Novell 3.11 network:π}ππprogram ServDate;ππuses Dos;ππtypeπ  tDateAndTime = recordπ    Year      : Byte;π    Month     : Byte;π    Day       : Byte;π    Hours     : Byte;π    Minutes   : Byte;π    Seconds   : Byte;π    DayOfWeek : Byteπ  end;ππ  String9 = string[ 9 ];ππconstπ  DayArray : array[ 0..6 ] of String9 =π             ( 'Sunday', 'Monday', 'Tuesday', 'Wednesday',π               'Thursday', 'Friday', 'Saturday' );ππ  MonthArray : array[ 1..12 ] of String9 =π               ( 'January', 'February', 'March', 'April', 'May', 'June',π                 'July', 'August', 'September', 'October', 'November',π                 'December' );πππfunction GetFileServerDateAndTime( var DTBuf : tDateAndTime ) : Byte;ππvar NovRegs : Registers;ππbeginπ  with NovRegs doπ  beginπ    AH := $E7;π    DS := Seg( DTBuf );π    DX := Ofs( DTBuf );π    MSDos( NovRegs );π    GetFileServerDateAndTime := ALπ  endπend;ππvarπ  DateAndTime : tDateAndTime;π  ResultCode  : Byte;ππbeginπ  ResultCode := GetFileServerDateAndTime( DateAndTime );π  if ResultCode = 0 thenπ    with DateAndTime doπ    beginπ      Write( 'File server date/time = ', DayArray[ DayOfWeek ], ', ',π             MonthArray[ Month ], ' ', Day );π      if ( Year < 80 ) thenπ        Write( ', 20', Year )π      elseπ        Write( ', 19', Year );π      WriteLn( ' at ', Hours, ':', Minutes, ':', Seconds )π    endπ  elseπ    WriteLn( 'Date/time call unsuccessful' )πend.π  2      05-26-9406:20ALL                      MARK BRAMWELL            NOVELL Library           SWAG9405            463    ,î   πUNIT Novell;π{---------------------------------------------------------------------------}π{                                                                           }π{  This UNIT provides a method of obtaining Novell information from a user  }π{  written program.  This UNIT was tested on an IBM AT running DOS 5.0 &    }π{  using Netware 2.15.  The unit compiled cleanly under Turbo Pascal 6.0    }π{                                                                           }π{  The UNIT has been updated to compile and run under Turbo Pascal for      }π{  Windows.                                                                 }π{                                                                           }π{  *** Tested ok with Netware 386 3.11  Sept/91                             }π{                                                                           }π{  Last Update:   11 Dec 91                                                 }π{                                                                           }π{---------------------------------------------------------------------------}π{                                                                           }π{  Any questions can be directed to:                                        }π{                                                                           }π{  Mark Bramwell                                                            }π{  University of Western Ontario                                            }π{  London, Ontario, N6A 3K7                                                 }π{                                                                           }π{  Phone:  519-473-3618 [work]              519-473-3618 [home]             }π{                                                                           }π{  Bitnet: mark@hamster.business.uwo.ca     Packet: ve3pzr @ ve3gyq         }π{                                                                           }π{  Anonymous FTP Server Internet Address: 129.100.22.100                    }π{                                                                           }π{---------------------------------------------------------------------------}ππ{ Any other Novell UNITS gladly accepted. }πππ{πmods February 1 1991, Ross Lazarus (rml@extro.ucc.su.AU.OZ)π     var retcodes in procedure getservername, get_broadcast_message,π     verify_object_password comments, password conversion to upper case,ππSeems to work fine on a Netware 3.00 and on 3.01 servers -π}πππINTERFACEππ{$IFDEF WINDOWS}πUses WinDos;π{$ENDIF WINDOWS}ππ{$IFNDEF WINDOWS}πUses Dos;π{$ENDIF WINDOWS}ππConstπ  Months : Array [1..12] of String[3] = ('JAN','FEB','MAR','APR','MAY','JUN',π                                         'JUL','AUG','SEP','OCT','NOV','DEC');ππ  HEXDIGITS : Array [0..15] of char = '0123456789ABCDEF';ππType    byte4 = array [1..4] of byte;ππ        byte6 = array [1..6] of byte;ππVARππ{----------------------------------------------------------------------}π{  The following values can be pulled from an user written application }π{                                                                      }π{  The programmer would first call   GetServerInfo.                    }π{  Then he could   writeln(serverinfo.name)   to print the server name }π{----------------------------------------------------------------------}ππ      ServerInfo    : Recordπ                     ReturnLength    : Integer;π                     Server          : Packed Array [1..48] of Byte;π                     NetwareVers     : Byte;π                     NetwareSubV     : Byte;π                     ConnectionMax   : array [1..2] of byte;π                     ConnectionUse   : array [1..2] of byte;π                     MaxConVol       : array [1..2] of byte; {}π                     OS_revision     : byte;π                     SFT_level       : byte;π                     TTS_level       : byte;π                     peak_used       : array [1..2] of byte;π                  accounting_version : byte;π                     vap_version     : byte;π                     queuing_version : byte;π                print_server_version : byte;π             virtual_console_version : byte;π       security_restrictions_version : byte;π        Internetwork_version_version : byte;π                        Undefined    : Packed Array [1..60] of Byte;π               peak_connections_used : integer;π                     Connections_max : integer;π                  Connections_in_use : integer;π               Max_connected_volumes : integer;π                                name : string;π                   End;πππprocedure get_server_lan_driver_information(var _lan_board_number : integer;π{ This will return info on what }           var _text1,_text2:string;π{ type of network cards are being }         var _network_address : byte4;π{ used in the server. }                     var _host_address : byte6;π                                            var _driver_installed,π                                                _option_number,π                                                _retcode : integer);ππprocedure GetConnectionInfo(var LogicalStationNo: integer;π                            var name,hex_id:string;π                            var conntype:integer;π                            var datetime:string;π                            var retcode:integer);π{ returns username and login date/time when you supply the station number. }ππprocedure clear_connection(connection_number : integer; var retcode :πinteger);π{ kicks the workstation off the server}ππprocedure GetHexID(var userid,hexid: string;π                   var retcode: integer);π{ returns the novell hexid of an username when you supply the username. }ππprocedure GetServerInfo;π{ returns various info of the default server }ππprocedure GetUser( var _station: integer;π                   var _username: string;π                   var retcode:integer);π{ returns logged-in station username when you supply the station number. }ππprocedure GetNode( var hex_addr: string;π                   var retcode: integer);π{ returns your physical network node in hex. }ππprocedure GetStation( var _station: integer;π                      var retcode: integer);π{ returns the station number of your workstation }ππprocedure GetServerName(var servername : string;π                        var retcode : integer);ππ{ returns the name of the current server }ππprocedure Send_Message_to_Username(username,message : string;π                                   var retcode: integer);π{ Sends a novell message to the userid's workstation }ππprocedure Send_Message_to_Station(station:integer;π                                  message : string;π                                  var retcode: integer);π{ Sends a message to the workstation station # }ππprocedure Get_Volume_Name(var volume_name: string;π                          volume_number: integer;π                          var retcode:integer);π{ Gets the Volume name from Novell network drive }π{ Example:  SYS    Note: default drive must be a }π{ network drive.                                 }ππprocedure get_realname(var userid:string;π                       var realname:string;π                       var retcode:integer);π{ You supply the userid, and it returns the realname as stored by syscon. }π{ Example:  userid=mbramwel   realname=Mark Bramwell }ππprocedure get_broadcast_mode(var bmode:integer);ππprocedure set_broadcast_mode(bmode:integer);ππprocedure get_broadcast_message(var bmessage: string;π                                var retcode : integer);ππprocedure get_server_datetime(var _year,_month,_day,_hour,_min,_sec,_dow:integer);π{ pulls from the server the date, time and Day Of Week }ππprocedure set_date_from_server;π{ pulls the date from the server and updates the workstation's clock }ππprocedure set_time_from_server;π{ pulls the time from the server and updates the workstation's clock }ππprocedure get_server_version(var _version : string);ππprocedure open_message_pipe(var _connection, retcode : integer);ππprocedure close_message_pipe(var _connection, retcode : integer);ππprocedure check_message_pipe(var _connection, retcode : integer);ππprocedure send_personal_message(var _connection : integer; var _message :πstring; var retcode : integer);ππprocedure get_personal_message(var _connection : integer; var _message :πstring; var retcode : integer);ππprocedure get_drive_connection_id(var drive_number,π                                  server_number : integer);π{pass the drive number - it returns the server number if a network volume}ππprocedure get_file_server_name(var server_number : integer;π                               var server_name : string);ππprocedure get_directory_path(var handle : integer;π                             var pathname : string;π                             var retcode : integer);ππprocedure get_drive_handle_id(var drive_number, handle_number : integer);ππprocedure set_preferred_connection_id(server_num : integer);ππprocedure get_preferred_connection_id(var server_num : integer);ππprocedure set_primary_connection_id(server_num : integer);ππprocedure get_primary_connection_id(var server_num : integer);ππprocedure get_default_connection_id(var server_num : integer);ππprocedure Get_Internet_Address(station : integer;π                               var net_number, node_addr, socket_number :πstring;π                               var retcode : integer);ππprocedure login_to_file_server(obj_type:integer; _name,_password : string;varπretcode:integer);ππprocedure logout;ππprocedure logout_from_file_server(var id: integer);ππprocedure down_file_server(flag:integer;var retcode : integer);ππprocedure detach_from_file_server(var id,retcode:integer);ππprocedure disable_file_server_login(var retcode : integer);ππprocedure enable_file_server_login(var retcode : integer);ππprocedure alloc_permanent_directory_handle(var _dir_handle : integer;π                                           var _drive_letter : string;π                                           var _dir_path_name : string;π                                           var _new_dir_handle : integer;π                                           var _effective_rights: byte;π                                           var _retcode : integer);ππprocedure map(var drive_spec:string;π              var _rights:byte;π              var _retcode : integer);ππprocedure scan_object(var last_object: longint;π                      var search_object_type: integer;π                      var search_object : string;π                      var replyid : longint;π                      var replytype : integer; var replyname : string;π                      var replyflag : integer; var replysecurity : byte;π                      var replyproperties : integer; var retcode : integer);ππprocedure verify_object_password(var object_type:integer; varπobject_name,password : string; var retcode : integer);ππ{--------------------------------------------------------------------------}π{ file locking routines }π{-----------------------}ππprocedure log_file(lock_directive:integer; log_filename: string;πlog_timeout:integer; var retcode:integer);ππprocedure clear_file_set;ππprocedure lock_file_set(lock_timeout:integer; var retcode:integer);ππprocedure release_file_set;ππprocedure release_file(log_filename: string; var retcode:integer);ππprocedure clear_file(log_filename: string; var retcode:integer);ππ{--------------------------------------------------------------------------π---}ππprocedure open_semaphore( _name:string;π                          _initial_value:shortint;π                          var _open_count:integer;π                          var _handle:longint;π                          var retcode:integer);ππprocedure close_semaphore(var _handle:longint; var retcode:integer);ππprocedure examine_semaphore(var _handle:longint; var _value:shortint; varπ_count, retcode:integer);ππprocedure signal_semaphore(var _handle:longint; var retcode:integer);ππprocedure wait_on_semaphore(var _handle:longint; _timeout:integer; varπretcode:integer);ππprocedure purge_all_erased_files(var retcode:integer);ππprocedure purge_erased_files(var retcode:integer);π{--------------------------------------------------------------------------π---}πππIMPLEMENTATIONππconstπ     zero = '0';ππvarπ   retcode : byte; { return code for all functions }ππ{$IFDEF WINDOWS}π  regs : TRegisters;   { Turbo Pascal for Windows }π{$ENDIF WINDOWS}ππ{$IFNDEF WINDOWS}π  regs : registers;    { Turbo Pascal for Dos }π{$ENDIF WINDOWS}ππprocedure get_volume_name(var volume_name: string; volume_number: integer;π                          var retcode:integer);π{πpulls volume names from default server.  Use set_preferred_connection_id toπset the default server.πretcodes:  0=ok, 1=no volume assigned  98h= # out of rangeπ}ππVARπ   count,count1  : integer;ππ   requestbuffer : recordπ      len        : integer;π      func       : byte;π      vol_num    : byte;π      end;ππ    replybuffer  : recordπ      len        : integer;π      vol_length : byte;π      name       : packed array [1..16] of byte;π      end;ππbeginπWith Regs doπbeginπ  ah := $E2;π  ds := seg(requestbuffer);π  si := ofs(requestbuffer);π  es := seg(replybuffer);π  di := ofs(replybuffer);π end;π With requestbuffer doπ beginπ  len  := 2;π  func := 6;π  vol_num := volume_number;  {passed from calling program}π end;π With replybuffer doπ beginπ  len :=  17;π  vol_length := 0;π  for count := 1 to 16 do name[count] := $00;π end;π msdos(Regs);π volume_name := '';π if replybuffer.vol_length > 0 thenπ    for count := 1 to replybuffer.vol_length doπ        volume_name := volume_name + chr(replybuffer.name[count]);π retcode := Regs.al;πend;ππprocedure verify_object_password(var object_type:integer; varπobject_name,password : string; var retcode : integer);π{πfor netware 3.xx remember to have previously (eg in the autoexec file )πset allow unencrypted passwords = onπon the console, otherwise this call always fails !πNote that intruder lockout status is affected by this call !πNetware security isn't that stupid....πPasswords appear to need to be converted to upper caseππretcode      apparent meaning as far as I can work out....ππ0            verification of object_name/password combinationπ197          account disabled due to intrusion lockoutπ214          unencrypted password calls not allowed on this v3+ serverπ252          no such object_name on this serverπ255          failure to verify object_name/password combinationππ}πvar  request_buffer : recordπ      buffer_length : integer;π        subfunction : byte;π           obj_type : array [1..2] of byte;π    obj_name_length : byte;π           obj_name : array [1..47] of byte;π    password_length : byte;π       obj_password : array [1..127] of byte;π                end;ππ       reply_buffer : recordπ      buffer_length : integer;π                end;ππ              count : integer;ππbeginπ     With request_buffer doπ     beginπ          buffer_length := 179;π          subfunction := $3F;π          obj_type[1] := 0;π          obj_type[2] := object_type;π          obj_name_length := 47;π          for count := 1 to 47 doπ              obj_name[count] := $00;π          for count := 1 to length(object_name) doπ          obj_name[count] := ord(object_name[count]);π          password_length := length(password);π          for count := 1 to 127 doπ              obj_password[count] := $00;π          if password_length > 0 thenπ             for count := 1 to password_length doπ                 obj_password[count] := ord(upcase(password[count]));π       end;π       With reply_buffer doπ            buffer_length := 0;π       With regs doπ       beginπ            Ah := $E3;π            Ds := Seg(Request_Buffer);π            Si := Ofs(Request_Buffer);π            Es := Seg(Reply_Buffer);π            Di := Ofs(Reply_Buffer);π       End;π       msdos(regs);π       retcode := regs.al;πend; { verify_object_password }ππππprocedure scan_object(var last_object: longint; var search_object_type:πinteger;π                      var search_object : string; var replyid : longint;π                      var replytype : integer; var replyname : string;π                      var replyflag : integer; var replysecurity : byte;π                      var replyproperties : integer; var retcode : integer);πvarπ    request_buffer : recordπ     buffer_length : integer;π       subfunction : byte;π         last_seen : longint;π       search_type : array [1..2] of byte;π       name_length : byte;π       search_name : array [1..47] of byte;π               end;ππ      reply_buffer : recordπ     buffer_length : integer;π         object_id : longint;π       object_type : array [1..2] of byte;π       object_name : array [1..48] of byte;π       object_flag : byte;π          security : byte;π        properties : byte;π               end;ππ             count : integer;ππbeginπwith request_buffer doπbeginπ buffer_length := 55;π subfunction := $37;π last_seen := last_object;π if search_object_type = -1 then { -1 = wildcard }π   beginπ   search_type[1] := $ff;π   search_type[2] := $ff;π   end elseπ   beginπ   search_type[1] := 0;π   search_type[2] := search_object_type;π   end;πname_length := length(search_object);πfor count := 1 to 47 do search_name[count] := $00;πif name_length > 0 then for count := 1 to name_length doπ   search_name[count] := ord(upcase(search_object[count]));πend;πWith reply_buffer doπbeginπ buffer_length := 57;π object_id:= 0;π object_type[1] := 0;π object_type[2] := 0;π for count := 1 to 48 do object_name[count] := $00;π object_flag := 0;π security := 0;π properties := 0;πend;πWith Regs Do Beginπ Ah := $E3;π Ds := Seg(Request_Buffer);π Si := Ofs(Request_Buffer);π Es := Seg(Reply_Buffer);π Di := Ofs(Reply_Buffer);πEnd;πmsdos(regs);πretcode := regs.al;πWith reply_buffer doπbeginπ replyflag := object_flag;π replyproperties := properties;π replysecurity := security;π replytype := object_type[2];π replyid := object_id;πend;πcount := 1;πreplyname := '';πWhile (count <= 48)  and (reply_buffer.Object_Name[count] <> 0) Do Beginπ    replyName := replyname + Chr(reply_buffer.Object_name[count]);π    count := count + 1;π    End { while };πend;πππprocedure alloc_permanent_directory_handleπ  (var _dir_handle : integer; var _drive_letter : string;π   var _dir_path_name : string; var _new_dir_handle : integer;π   var _effective_rights: byte; var _retcode : integer);ππvar request_buffer : recordπ     buffer_length : integer;π       subfunction : byte;π        dir_handle : byte;π      drive_letter : byte;π   dir_path_length : byte;π     dir_path_name : packed array [1..255] of byte;π               end;ππ      reply_buffer : recordπ     buffer_length : integer;π    new_dir_handle : byte;π  effective_rights : byte;π               end;ππ  count : integer;ππbeginπWith request_buffer doπbeginπ buffer_length := 259;π subfunction := $12;π dir_handle := _dir_handle;π drive_letter := ord(upcase(_drive_letter[1]));π dir_path_length := length(_dir_path_name);π for count := 1 to 255 do dir_path_name[count] := $0;π if dir_path_length > 0 then for count := 1 to dir_path_length doπ    dir_path_name[count] := ord(upcase(_dir_path_name[count]));πend;πWith reply_buffer doπbeginπ buffer_length := 2;π new_dir_handle := 0;π effective_rights := 0;πend;πWith Regs Do Beginπ Ah := $E2;π Ds := Seg(Request_Buffer);π Si := Ofs(Request_Buffer);π Es := Seg(Reply_Buffer);π Di := Ofs(Reply_Buffer);πEnd;πmsdos(regs);π_retcode := regs.al;π_effective_rights := $0;π_new_dir_handle := $0;πif _retcode = 0 thenπbeginπ _effective_rights := reply_buffer.effective_rights;π _new_dir_handle := reply_buffer.new_dir_handle;πend;πend;ππprocedure map(var drive_spec:string; var _rights:byte; var _retcode :πinteger);πvarπ    dir_handle : integer;π     path_name : string;π        rights : byte;π  drive_number : integer;π  drive_letter : string;π    new_handle : integer;π       retcode : integer;ππbeginπ {first thing is we strip leading and trailing blanks}π while drive_spec[1]=' ' do  drive_spec :=πcopy(drive_spec,2,length(drive_spec));π while drive_spec[length(drive_spec)]=' ' do  drive_spec :=πcopy(drive_spec,1,length(drive_spec)-1);π drive_number := ord(upcase(drive_spec[1]))-65;π drive_letter := upcase(drive_spec[1]);π path_name := copy(drive_spec,4,length(drive_spec));π get_drive_handle_id(drive_number,dir_handle);π alloc_permanent_directory_handle(dir_handle,drive_letter,path_name,new_handle,π rights,retcode);π _retcode := retcode;π _rights := rights;πend;πππππprocedure down_file_server(flag:integer;var retcode : integer);πvarππrequest_buffer : recordπ buffer_length : integer;π   subfunction : byte;π     down_flag : byte;π           end;ππ  reply_buffer : recordπ buffer_length : integer;π           end;ππbeginπWith request_buffer doπbeginπ buffer_length := 2;π subfunction := $D3;π down_flag := flag;πend;πreply_buffer.buffer_length := 0;πWith Regs Do Beginπ Ah := $E3;π Ds := Seg(Request_Buffer);π Si := Ofs(Request_Buffer);π Es := Seg(Reply_Buffer);π Di := Ofs(Reply_Buffer);πEnd;πmsdos(regs);πretcode := regs.al;πend;πππprocedure set_preferred_connection_id(server_num : integer);πbeginπ regs.ah := $F0;π regs.al := $00;π regs.ds := 0;π regs.es := 0;π regs.dl := server_num;π msdos(regs);πend;ππprocedure set_primary_connection_id(server_num : integer);πbeginπ regs.ah := $F0;π regs.al := $04;π regs.ds := 0;π regs.es := 0;π regs.dl := server_num;π msdos(regs);πend;ππprocedure get_primary_connection_id(var server_num : integer);πbeginπ regs.ah := $F0;π regs.al := $05;π regs.es := 0;π regs.ds := 0;π msdos(regs);π server_num := regs.al;πend;ππprocedure get_default_connection_id(var server_num : integer);πbeginπ regs.ah := $F0;π regs.al := $02;π regs.es := 0;π regs.ds := 0;π msdos(regs);π server_num := regs.al;πend;ππprocedure get_preferred_connection_id(var server_num : integer);πbeginπ regs.ah := $F0;π regs.al := $02;π regs.ds := 0;π regs.es := 0;π msdos(regs);π server_num := regs.al;πend;πππprocedure get_drive_connection_id(var drive_number, server_number : integer);πvarππ drive_table : array [1..32] of byte;π       count : integer;π           p : ^byte;ππbeginπ  regs.ah := $EF;π  regs.al := $02;π  regs.es := 0;π  regs.ds := 0;π  msdos(regs);π  p := ptr(regs.es, regs.si);π  move(p^,drive_table,32);π  if ((drive_number < 0) or (drive_number > 32))  then drive_number := 1;π  server_number := drive_table[drive_number];πend;ππprocedure get_drive_handle_id(var drive_number, handle_number : integer);πvarπ drive_table : array [1..32] of byte;π       count : integer;π           p : ^byte;ππbeginπ  regs.ah := $EF;π  regs.al := $00;π  regs.ds := 0;π  regs.es := 0;π  msdos(regs);π  p := ptr(regs.es, regs.si);π  move(p^,drive_table,32);π  if ((drive_number < 0) or (drive_number > 32))  then drive_number := 1;π  handle_number := drive_table[drive_number];πend;πππprocedure get_file_server_name(var server_number : integer; var server_name :πstring);πvarπ  name_table : array [1..8*48] of byte;π      server : array [1..8] of string;π       count : integer;π      count2 : integer;π           p : ^byte;π     no_more : integer;ππbeginπ  regs.ah := $EF;π  regs.al := $04;π  regs.ds := 0;π  regs.es := 0;π  msdos(regs);π  no_more := 0;π  p := ptr(regs.es, regs.si);π  move(p^,name_table,8*48);π  for count := 1 to 8 do server[count] := '';π  for count := 0 to 7 doπ  beginπ    no_more := 0;π    for count2 := (count*48)+1 to (count*48)+48 do if name_table[count2] <>π$00π        thenπ        beginπ        if no_more=0 then server[count+1] := server[count+1] +πchr(name_table[count2]);π        end else no_more:=1; {scan until 00h is found}π  end;π  if ((server_number<1) or (server_number>8)) then server_number := 1;π  server_name := server[server_number];πend;ππprocedure disable_file_server_login(var retcode : integer);πvar  request_buffer : recordπ      buffer_length : integer;π        subfunction : byteπ                end;ππ  reply_buffer : recordπ buffer_length : integer;π           end;ππbeginπ  With Regs Do Beginπ    Ah := $E3;π    Ds := Seg(Request_Buffer);π    Si := Ofs(Request_Buffer);π    Es := Seg(Reply_Buffer);π    Di := Ofs(Reply_Buffer);π  End;π  With request_buffer doπ   beginπ   buffer_length := 1;π   subfunction := $CB;π   end;π reply_buffer.buffer_length := 0;π msdos(regs);π retcode := regs.al;πend;ππprocedure enable_file_server_login(var retcode : integer);πvar request_buffer : recordπ     buffer_length : integer;π       subfunction : byteπ               end;ππ  reply_buffer : recordπ buffer_length : integer;π           end;ππbeginπ  With Regs Do Beginπ    Ah := $E3;π    Ds := Seg(Request_Buffer);π    Si := Ofs(Request_Buffer);π    Es := Seg(Reply_Buffer);π    Di := Ofs(Reply_Buffer);π  End;π  With request_buffer doπ   beginπ   buffer_length := 1;π   subfunction := $CC;π   end;π reply_buffer.buffer_length := 0;π msdos(regs);π retcode := regs.al;πend;πππprocedure get_directory_path(var handle : integer; var pathname : string; varπretcode : integer);πvar count : integer;ππ   request_buffer : recordπ              len : integer;π      subfunction : byte;π       dir_handle : byte;π              end;ππ     reply_buffer : recordπ              len : integer;π         path_len : byte;π        path_name : array [1..255] of byte;π              end;ππbeginπ  With Regs Do Beginπ    Ah := $e2;π    Ds := Seg(Request_Buffer);π    Si := Ofs(Request_Buffer);π    Es := Seg(Reply_Buffer);π    Di := Ofs(Reply_Buffer);π  End;π  With request_buffer doπ   beginπ   len := 2;π   subfunction := $01;π   dir_handle := handle;π   end;π  With reply_buffer doπ   beginπ   len := 256;π   path_len := 0;π   for count := 1 to 255 do path_name[count] := $00;π   end;π  msdos(regs);π  retcode := regs.al;π  pathname := '';π  if reply_buffer.path_len > 0 then for count := 1 to reply_buffer.path_len doπ     pathname := pathname + chr(reply_buffer.path_name[count]);πend;ππprocedure detach_from_file_server(var id,retcode:integer);πbeginπ regs.ah := $F1;π regs.al := $01;π regs.dl := id;π msdos(regs);π retcode := regs.al;πend;πππprocedure getstation( var _station: integer; var retcode: integer);πbeginπ   With Regs doπ   beginπ    ah := $DC;π    ds := 0;π    si := 0;π   end;π   MsDos( Regs );π   _station := Regs.al;π   retcode := 0;π   end;πππprocedure GetHexID( var userid,hexid: string; var retcode: integer);πvarπ    i,x           : integer;π    hex_id        : string;π    requestbuffer : recordπ      len      : integer;π      func     : byte;π      conntype : packed array [1..2] of byte;π      name_len : byte;π      name     : packed array [1..47] of char;π      end;π    replybuffer   : recordπ      len      : integer;π      uniqueid1: packed array [1..2] of byte;π      uniqueid2: packed array [1..2] of byte;π      conntype : word;π      name     : packed array [1..48] of byte;π      end;ππbeginπ  regs.ah := $E3;π  requestbuffer.func := $35;π  regs.ds := seg(requestbuffer);π  regs.si := ofs(requestbuffer);π  regs.es := seg(replybuffer);π  regs.di := ofs(replybuffer);π  requestbuffer.len := 52;π  replybuffer.len := 55;π  requestbuffer.name_len := length(userid);π  for i := 1 to length(userid) do requestbuffer.name[i] := userid[i];π  requestbuffer.conntype[2] := $1;π  requestbuffer.conntype[1] := $0;π  replybuffer.conntype := 1;π  msdos(regs);π  retcode := regs.al;   {π  if retcode = $96 then writeln('Server out of memory');π  if retcode = $EF then writeln('Invalid name');π  if retcode = $F0 then writeln('Wildcard not allowed');π  if retcode = $FC then writeln('No such object *',userid,'*');π  if retcode = $FE then writeln('Server bindery locked');π  if retcode = $FF then writeln('Bindery failure'); }π  hex_id := '';π  if retcode = 0 thenπ  beginπ   hex_id := hexdigits[replybuffer.uniqueid1[1] shr 4];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid1[1] and $0F];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid1[2] shr 4];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid1[2] and $0F];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid2[1] shr 4];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid2[1] and $0F];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid2[2] shr 4];π   hex_id := hex_id + hexdigits[replybuffer.uniqueid2[2] and $0F];π   { Now we chop off leading zeros }π   while hex_id[1] = '0' do hex_id := copy(hex_id,2,length(hex_id));π  end;π   hexid := hex_id;πend;πππProcedure GetConnectionInfoπ(Var LogicalStationNo: Integer; Var Name: String; Var HEX_ID: String;π Var ConnType : Integer; Var DateTime : String; Var retcode:integer);ππVarπ  I,X            : Integer;π  RequestBuffer  : Recordπ                     PacketLength : Integer;π                     FunctionVal  : Byte;π                     ConnectionNo : Byte;π                   End;π  ReplyBuffer    : Recordπ                     ReturnLength : Integer;π                     UniqueID1    : Packed Array [1..2] of byte;π                     UniqueID2    : Packed Array [1..2] of byte;π                     NWConnType   : Packed Array [1..2] of byte;π                     ObjectName   : Packed Array [1..48] of Byte;π                     LoginTime    : Packed Array [1..8] of Byte;π                   End;π  Month          : String[3];π  Year,π  Day,π  Hour,π  Minute         : String[2];ππBeginπ  With RequestBuffer Do Beginπ    PacketLength := 2;π    FunctionVal := 22;  { 22 = Get Station Info }π    ConnectionNo := LogicalStationNo;π  End;π  ReplyBuffer.ReturnLength := 62;π  With Regs Do Beginπ    Ah := $e3;π    ds := 0;π    es := 0;π    Ds := Seg(RequestBuffer);π    Si := Ofs(RequestBuffer);π    Es := Seg(ReplyBuffer);π    Di := Ofs(ReplyBuffer);π  End;π  MsDos(Regs);π  retcode := regs.al;π  name := '';π  hex_id := hexdigits[replybuffer.uniqueid1[1] shr 4];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid1[1] and $0F];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid1[2] shr 4];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid1[2] and $0F];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid2[1] shr 4];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid2[1] and $0F];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid2[2] shr 4];π  hex_id := hex_id + hexdigits[replybuffer.uniqueid2[2] and $0F];π  { Now we chop off leading zeros }π    while ( (hex_id[1]='0') and (length(hex_id) > 1) )π             do hex_id := copy(hex_id,2,length(hex_id));π  ConnType := replybuffer.nwconntype[2];π  datetime := '';π  If hex_id <> '0' Then Begin {Grab username}π    With ReplyBuffer Do Beginπ      I := 1;π      While (I <= 48)  and (ObjectName[I] <> 0) Doπ        Beginπ        Name[I] := Chr(Objectname[I]);π        I := I + 1;π        End { while };π     Name[0] := Chr(I - 1);π   End; {With} End; {if}π   If hex_id <> '0' then With replybuffer do {Grab login time}π   beginπ     Str(LoginTime[1]:2,Year);π     Month := Months[LoginTime[2]];π     Str(LoginTime[3]:2,Day);π     Str(LoginTime[4]:2,Hour);π     Str(LoginTime[5]:2,Minute);π     If Day[1] = ' ' Then Day[1] := '0';π     If Hour[1] = ' ' Then Hour[1] := '0';π     If Minute[1] = ' ' Then Minute[1] := '0';π     DateTime := Day+'-'+Month+'-'+Year+' ' + Hour + ':' + Minute;π     End;πEnd { GetConnectInfo };ππprocedure login_to_file_server(obj_type:integer;_name,_password : string;varπretcode:integer);πvar   request_buffer : recordπ            B_length : integer;π         subfunction : byte;π              o_type : packed array [1..2] of byte;π         name_length : byte;π            obj_name : packed array [1..47] of byte;π     password_length : byte;π            password : packed array [1..27] of byte;π                 end;ππ        reply_buffer : recordπ            R_length : integer;π                 end;ππ               count : integer;ππbeginπWith request_buffer doπbeginπ B_length := 79;π subfunction := $14;π o_type[1] := 0;π o_type[2] := obj_type;π for count := 1 to 47 do obj_name[count] := $0;π for count := 1 to 27 do password[count] := $0;π if length(_name) > 0 thenπ    for count := 1 to length(_name) doπobj_name[count]:=ord(upcase(_name[count]));π if length(_password) > 0 thenπ    for count := 1 to length(_password) doπpassword[count]:=ord(upcase(_password[count]));π {set to full length of field}π name_length := 47;π password_length := 27;πend;πWith reply_buffer doπbeginπ R_length := 0;πend;π  With Regs Do Beginπ    Ah := $e3;π    Ds := Seg(Request_Buffer);π    Si := Ofs(Request_Buffer);π    Es := Seg(reply_buffer);π    Di := Ofs(reply_buffer);π  End;π  MsDos(Regs);π  retcode := regs.alπend;ππprocedure logout;π{logout from all file servers}πbeginπ regs.ah := $D7;π msdos(regs);πend;ππprocedure logout_from_file_server(var id: integer);π{logout from one file server}πbeginπ regs.ah := $F1;π regs.al := $02;π regs.dl := id;π msdos(regs);πend;πππππprocedure send_message_to_username(username,message : string; var retcode:πinteger);πVARπ   count1     : byte;π   userid     : string;π   stationid  : integer;π   ret_code   : integer;ππbeginπ   ret_code := 1;π   for count1:= 1 to length(username) doπ       username[count1]:=upcase(username[count1]); { Convert to upper case }π   getserverinfo;π   for count1:= 1 to serverinfo.connections_max doπ   beginπ     stationid := count1;π     getuser( stationid, userid, retcode);π      if userid = username thenπ        beginπ        ret_code := 0;π        send_message_to_station(stationid, message, retcode);π      end;π     end; { end of count }π     retcode := ret_code;π     { retcode = 0 if sent,  1 if userid not found }πend; { end of procedure }πππProcedure GetServerInfo;πVarπ  RequestBuffer  : Recordπ                     PacketLength : Integer;π                     FunctionVal  : Byte;π                   End;π  I              : Integer;ππBeginπ  With RequestBuffer Do Beginπ    PacketLength := 1;π    FunctionVal := 17;  { 17 = Get Server Info }π  End;π  ServerInfo.ReturnLength := 128;π  With Regs Do Beginπ    Ah := $e3;π    Ds := Seg(RequestBuffer);π    Si := Ofs(RequestBuffer);π    Es := Seg(ServerInfo);π    Di := Ofs(ServerInfo);π  End;π  MsDos(Regs);π  With serverinfo doπ  beginπ   connections_max := connectionmax[1]*256 + connectionmax[2];π   connections_in_use := connectionuse[1]*256 + connectionuse[2];π   max_connected_volumes := maxconvol[1]*256 + maxconvol[2];π   peak_connections_used := peak_used[1]*256 + peak_used[2];π   name := '';π   i := 1;π   while ((server[i] <> 0) and (i<>48)) doπ    beginπ    name := name + chr(server[i]);π    i := i + 1;π    end;π   end;πEnd;ππprocedure GetServerName(var servername : string; var retcode : integer);π{-----------------------------------------------------------------}π{ This routine returns the same as GetServerInfo.  This routine   }π{ was kept to maintain compatibility with the older  novell unit. }π{-----------------------------------------------------------------}πbeginπ  getserverinfo;π  servername := serverinfo.name;π  retcode := 0;π  end;ππprocedure send_message_to_station(station:integer; message : string; var retcode : integer);πVARπ   req_buffer : recordπ   buffer_len : integer;π   subfunction: byte;π      c_count : byte;π       c_list : byte;π   msg_length : byte;π          msg : packed array [1..55] of byte;π          end;ππ   rep_buffer : recordπ   buffer_len : integer;π      c_count : byte;π       r_list : byte;π          end;ππ   count1     : integer;ππbeginπ        if length(message) > 55 then message:=copy(message,1,55);π        With Regs doπ        beginπ         ah := $E1;π         ds:=seg(req_buffer);π         si:=ofs(req_buffer);π         es:=seg(rep_buffer);π         di:=ofs(rep_buffer);π        End;π        With req_buffer doπ        beginπ         buffer_len := 59;π         subfunction := 00;π         c_count := 1;π         c_list := station;π         for count1:= 1 to 55 do msg[count1]:= $00; { zero the buffer }π         msg_length := length(message); { message length }π         for count1:= 1 to length(message) doπmsg[count1]:=ord(message[count1]);π        End;π        With rep_buffer doπ        beginπ         buffer_len := 2;π         c_count := 1;π         r_list := 0;π        End;π        msdos( Regs );π        retcode:= rep_buffer.r_list;π   end;πππprocedure getuser( var _station: integer; var  _username: string; var retcode:πinteger);π{This procedure provides a shorter method of obtaining just the USERID.}πvarπ     gu_hexid : string;π  gu_conntype : integer;π  gu_datetime : string;ππbeginπ  getconnectioninfo(_station,_username,gu_hexid,gu_conntype,gu_datetime,retcode);πend;πππPROCEDURE GetNode( var hex_addr: string; var retcode: integer );π{ get the physical station address }ππConstπ   Hex_Set  :packed array[0..15] of char = '0123456789ABCDEF';ππBegin { GetNode }π   {Get the physical address from the Network Card}π   Regs.Ah := $EE;π   regs.ds := 0;π   regs.es := 0;π   MsDos(Regs);π   hex_addr := '';π   hex_addr := hex_addr + hex_set[(regs.ch shr 4)];π   hex_addr := hex_addr + hex_set[(regs.ch and $0f)];π   hex_addr := hex_addr + hex_set[(regs.cl shr 4) ];π   hex_addr := hex_addr + hex_set[(regs.cl and $0f)];π   hex_addr := hex_addr + hex_set[(regs.bh shr 4)];π   hex_addr := hex_addr + hex_set[(regs.bh and $0f)];π   hex_addr := hex_addr + hex_set[(regs.bl shr 4)];π   hex_addr := hex_addr + hex_set[(regs.bl and $0f)];π   hex_addr := hex_addr + hex_set[(regs.ah shr 4)];π   hex_addr := hex_addr + hex_set[(regs.ah and $0f)];π   hex_addr := hex_addr + hex_set[(regs.al shr 4)];π   hex_addr := hex_addr + hex_set[(regs.al and $0f)];π   retcode := 0;πEnd; { Getnode }πππPROCEDURE Get_Internet_Address(station : integer; var net_number, node_addr,πsocket_number : string; var retcode : integer);πππConstπ   Hex_Set  :packed array[0..15] of char = '0123456789ABCDEF';ππVar   Request_buffer : recordπ              length : integer;π         subfunction : byte;π          connection : byte;π                 end;ππ    Reply_Buffer : recordπ          length : integer;π         network : array [1..4] of byte;π            node : array [1..6] of byte;π          socket : array [1..2] of byte;π             end;ππ           count : integer;π      _node_addr : string;π  _socket_number : string;π     _net_number : string;ππbeginπ With Regs doπ beginπ  ah := $E3;π  ds:=seg(request_buffer);π  si:=ofs(request_buffer);π  es:=seg(reply_buffer);π  di:=ofs(reply_buffer);π End;π With request_buffer doπ beginπ  length := 2;π  subfunction := $13;π  connection := station;π end;π With reply_buffer doπ beginπ  length := 12;π  for count := 1 to 4 do network[count] := 0;π  for count := 1 to 6 do node[count] := 0;π  for count := 1 to 2 do socket[count] := 0;π end;π msdos(regs);π retcode := regs.al;π _net_number := '';π _node_addr := '';π _socket_number := '';π if retcode = 0 thenπ beginπ for count := 1 to 4 doπ     beginπ     _net_number := _net_number + hex_set[ (reply_buffer.network[count] shr 4)π];π     _net_number := _net_number + hex_set[ (reply_buffer.network[count] andπ$0F) ];π     end;π for count := 1 to 6 doπ     beginπ     _node_addr := _node_addr + (hex_set[ (reply_buffer.node[count] shr 4) ]);π     _node_addr := _node_addr + (hex_set[ (reply_buffer.node[count] and $0F)π]);π     end;π for count := 1 to 2 doπ     beginπ     _socket_number := _socket_number + (hex_set[ (reply_buffer.socket[count]πshr 4) ]);π     _socket_number := _socket_number + (hex_set[ (reply_buffer.socket[count]πand $0F) ]);π     end;π end; {end of retcode=0}π net_number := _net_number;π node_addr := _node_addr;π socket_number := _socket_number;π end;ππprocedure get_realname(var userid,realname:string; var retcode:integer);πvarπ    requestbuffer : recordπ    buffer_length : array [1..2] of byte;π      subfunction : byte;π      object_type : array [1..2] of byte;π    object_length : byte;π      object_name : array [1..47] of byte;π          segment : byte;π  property_length : byte;π    property_name : array [1..14] of byte;π    end;ππ      replybuffer : recordπ    buffer_length : array [1..2] of byte;π   property_value : array [1..128] of byte;π    more_segments : byte;π   property_flags : byte;π   end;ππ   count    : integer;π   id       : string;π   fullname : string;ππbeginπ  id := 'IDENTIFICATION';π  With requestbuffer do beginπ     buffer_length[2] := 0;π     buffer_length[1] := 69;π     subfunction  := $3d;π     object_type[1]:= 0;π     object_type[2]:= 01;π     segment := 1;π     object_length := 47;π     property_length := length(id);π     for count := 1 to 47 do object_name[count] := $0;π     for count := 1 to length(userid) do object_name[count] :=πord(userid[count]);π     for count := 1 to 14 do property_name[count] := $0;π     for count := 1 to length(id) do property_name[count] := ord(id[count]);π     end;π  With replybuffer do beginπ     buffer_length[1] := 130;π     buffer_length[2] := 0;π     for count := 1 to 128 do property_value[count] := $0;π     more_segments := 1;π     property_flags := 0;π     end;π  With Regs do beginπ     Ah := $e3;π     Ds := Seg(requestbuffer);π     Si := Ofs(requestbuffer);π     Es := Seg(replybuffer);π     Di := Ofs(replybuffer);π     end;π  MSDOS(Regs);π  retcode := Regs.al;π  fullname := '';π  count := 1;π  if replybuffer.property_value[1] <> 0 thenπ  repeatπ   beginπ   if replybuffer.property_value[count]<>0π      then fullname := fullname + chr(replybuffer.property_value[count]);π   count := count + 1;π   end;π   until ((count=128) or (replybuffer.property_value[count]=0));π  {if regs.al = $96 then writeln('server out of memory');π  if regs.al = $ec then writeln('no such segment');π  if regs.al = $f0 then writeln('wilcard not allowed');π  if regs.al = $f1 then writeln('invalid bindery security');π  if regs.al = $f9 then writeln('no property read priv');π  if regs.al = $fb then writeln('no such property');π  if regs.al = $fc then writeln('no such object');}π  if retcode=0 then realname := fullname else realname:='';πend;ππprocedure get_broadcast_mode(var bmode:integer);πbeginπ regs.ah := $de;π regs.dl := $04;π msdos(regs);π bmode := regs.al;πend;ππprocedure set_broadcast_mode(bmode:integer);πbeginπ if ((bmode > 3) or (bmode < 0)) then bmode := 0;π regs.ah := $de;π regs.dl := bmode;π msdos(regs);π bmode := regs.al;πend;ππprocedure get_broadcast_message(var bmessage: string; var retcode : integer);πvar requestbuffer : recordπ     bufferlength : array [1..2] of byte;π      subfunction : byte;π      end;ππ      replybuffer : recordπ     bufferlength : array [1..2] of byte;π    messagelength : byte;π          message : array [1..58] of byte;π          end;π    count : integer;ππbeginπ  With Requestbuffer do beginπ     bufferlength[1] := 1;π     bufferlength[2] := 0;π     subfunction := 1;π     end;π  With replybuffer do beginπ     bufferlength[1] := 59;π     bufferlength[2] := 0;π     messagelength := 0;π     end;π     for count := 1 to 58 do replybuffer.message[count] := $0;ππ  With Regs do beginπ     Ah := $e1;π     Ds := Seg(requestbuffer);π     Si := Ofs(requestbuffer);π     Es := Seg(replybuffer);π     Di := Ofs(replybuffer);π     end;π  MSDOS(Regs);π  retcode := Regs.al;π  bmessage := '';π  count := 0;π  if replybuffer.messagelength > 58 then replybuffer.messagelength := 58;π  if replybuffer.messagelength > 0 thenπ     for count := 1 to replybuffer.messagelength doπ     bmessage := bmessage + chr(replybuffer.message[count]);π  { retcode = 0 if no message,  1 if message was retreived }π  if length(bmessage) = 0 then retcode := 1 else retcode := 0;π  end;ππprocedure get_server_datetime(var _year,_month,_day,_hour,_min,_sec,_dow:integer);πvar replybuffer : recordπ           year : byte;π          month : byte;π            day : byte;π           hour : byte;π         minute : byte;π         second : byte;π            dow : byte;π            end;ππbeginπ  With Regs do beginπ     Ah := $e7;π     Ds := Seg(replybuffer);π     Dx := Ofs(replybuffer);π     end;π  MSDOS(Regs);π  retcode := Regs.al;π  _year := replybuffer.year;π  _month := replybuffer.month;π  _day := replybuffer.day;π  _hour := replybuffer.hour;π  _min := replybuffer.minute;π  _sec := replybuffer.second;π  _dow := replybuffer.dow;πend;ππprocedure set_date_from_server;πvar replybuffer : recordπ           year : byte;π          month : byte;π            day : byte;π           hour : byte;π         minute : byte;π         second : byte;π            dow : byte;π            end;ππbeginπ  With Regs do beginπ     Ah := $e7;π     Ds := Seg(replybuffer);π     Dx := Ofs(replybuffer);π     end;π  MSDOS(Regs);π  setdate(replybuffer.year+1900,replybuffer.month,replybuffer.day);πend;ππprocedure set_time_from_server;πvar replybuffer : recordπ           year : byte;π          month : byte;π            day : byte;π           hour : byte;π         minute : byte;π         second : byte;π            dow : byte;π            end;ππbeginπ  With Regs do beginπ     Ah := $e7;π     Ds := Seg(replybuffer);π     Dx := Ofs(replybuffer);π     end;π  MSDOS(Regs);π  settime(replybuffer.hour,replybuffer.minute,replybuffer.second,0);πend;ππprocedure get_server_version(var _version : string);πvar  count,x : integer;ππ       request_buffer : recordπ        buffer_length : integer;π          subfunction : byte;π          end;ππ         reply_buffer : recordπ        buffer_length : integer;π                stuff : array [1..512] of byte;π                end;ππ        strings : array [1..3] of string;πbeginπ  With Regs do beginπ     Ah := $e3;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  With request_buffer doπ  beginπ     buffer_length := 1;π     subfunction := $c9;π  end;π  With reply_buffer doπ  beginπ     buffer_length := 512;π     for count := 1 to 512 do stuff[count] := $00;π  end;π  MSDOS(Regs);π  for count := 1 to 3 do strings[count] := '';π  x := 1;π  With reply_buffer doπ  beginπ    for count := 1 to 256 doπ    beginπ     if stuff[count] <> $0 thenπ        beginπ         if not ((stuff[count]=32) and (strings[x]='')) then strings[x] :=πstrings[x] + chr(stuff[count]);π        end;π     if stuff[count] = $0 then if x <> 3 then x := x + 1;π    end;π  End; { end of with }π  _version := strings[2];πend;ππprocedure open_message_pipe(var _connection, retcode : integer);πvar  request_buffer : recordπ      buffer_length : integer;π        subfunction : byte;π   connection_count : byte;π    connection_list : byte;π                end;ππ      reply_buffer : recordπ     buffer_length : integer;π  connection_count : byte;π       result_list : byte;π               end;πbeginπ  With Regs do beginπ     Ah := $e1;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  With request_buffer doπ  beginπ     buffer_length := 3;π     subfunction := $06;π     connection_count := $01;π     connection_list := _connection;π  end;π  With reply_buffer doπ  beginπ     buffer_length := 2;π     connection_count := 0;π     result_list := 0;π  end;π  MSDOS(Regs);π  retcode := reply_buffer.result_list;πend;ππprocedure close_message_pipe(var _connection, retcode : integer);πvar  request_buffer : recordπ      buffer_length : integer;π        subfunction : byte;π   connection_count : byte;π    connection_list : byte;π                end;ππ      reply_buffer : recordπ     buffer_length : integer;π  connection_count : byte;π       result_list : byte;π               end;πbeginπ  With Regs do beginπ     Ah := $e1;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  With request_buffer doπ  beginπ     buffer_length := 3;π     subfunction := $07;π     connection_count := $01;π     connection_list := _connection;π  end;π  With reply_buffer doπ  beginπ     buffer_length := 2;π     connection_count := 0;π     result_list := 0;π  end;π  MSDOS(Regs);π  retcode := reply_buffer.result_list;πend;ππprocedure check_message_pipe(var _connection, retcode : integer);πvar request_buffer : recordπ     buffer_length : integer;π       subfunction : byte;π  connection_count : byte;π   connection_list : byte;π               end;ππ      reply_buffer : recordπ     buffer_length : integer;π  connection_count : byte;π       result_list : byte;π               end;πbeginπ  With Regs do beginπ     Ah := $e1;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  With request_buffer doπ  beginπ     buffer_length := 3;π     subfunction := $08;π     connection_count := $01;π     connection_list := _connection;π  end;π  With reply_buffer doπ  beginπ     buffer_length := 2;π     connection_count := 0;π     result_list := 0;π  end;π  MSDOS(Regs);π  retcode := reply_buffer.result_list;πend;πππprocedure send_personal_message(var _connection : integer; var _message :πstring; var retcode : integer);πvar count : integer;ππ      request_buffer : recordπ       buffer_length : integer;π         subfunction : byte;π    connection_count : byte;π     connection_list : byte;π      message_length : byte;π             message : array [1..126] of byte;π                 end;ππ        reply_buffer : recordπ       buffer_length : integer;π    connection_count : byte;π         result_list : byte;π                 end;ππbeginπ  With Regs do beginπ     Ah := $e1;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  With request_buffer doπ  beginπ     subfunction := $04;π     connection_count := $01;π     connection_list := _connection;π     message_length := length(_message);π     buffer_length := length(_message) + 4;π     for count := 1 to 126 do message[count] := $00;π     if message_length > 0 then for count := 1 to message_length doπ        message[count] := ord(_message[count]);π  end;π  With reply_buffer doπ  beginπ     buffer_length := 2;π     connection_count := 0;π     result_list := 0;π  end;π  MSDOS(Regs);π  retcode := reply_buffer.result_list;πend;ππprocedure purge_erased_files(var retcode:integer);πvar  request_buffer : recordπ      buffer_length : integer;π        subfunction : byte;π                end;ππ       reply_buffer : recordπ      buffer_length : integer;π                end;πbeginπ  With request_buffer doπ    beginπ    buffer_length := 1;π    subfunction := $10;π    end;π  With reply_buffer do buffer_length := 0;π  With Regs do beginπ   Ah := $E2;π   Ds := Seg(request_buffer);π   Si := Ofs(request_buffer);π   Es := Seg(reply_buffer);π   Di := Ofs(reply_buffer);π   end;π  msdos(regs);π  retcode := regs.al;πend;ππprocedure purge_all_erased_files(var retcode:integer);πvar  request_buffer : recordπ      buffer_length : integer;π        subfunction : byte;π                end;ππ       reply_buffer : recordπ      buffer_length : integer;π                end;πbeginπ  With request_buffer doπ    beginπ    buffer_length := 1;π    subfunction := $CE;π    end;π  With reply_buffer do buffer_length := 0;π  With Regs do beginπ   Ah := $E3;π   Ds := Seg(request_buffer);π   Si := Ofs(request_buffer);π   Es := Seg(reply_buffer);π   Di := Ofs(reply_buffer);π   end;π  msdos(regs);π  retcode := regs.al;πend;πππprocedure get_personal_message(var _connection : integer; var _message :πstring; var retcode : integer);πvar count : integer;ππ      request_buffer : recordπ       buffer_length : integer;π         subfunction : byte;π                 end;ππ        reply_buffer : recordπ       buffer_length : integer;π   source_connection : byte;π      message_length : byte;π      message_buffer : array [1..126] of byte;π                 end;ππbeginπ    With Regs do beginπ     Ah := $e1;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  With request_buffer doπ  beginπ     buffer_length := 1;π     subfunction := $05;π  end;π  With reply_buffer doπ  beginπ     buffer_length := 128;π     source_connection := 0;π     message_length := 0;π     for count := 1 to 126 do message_buffer[count] := $0;π  end;π  MSDOS(Regs);π  _connection := reply_buffer.source_connection;π  _message := '';π  retcode := reply_buffer.message_length;π  if retcode > 0 then for count := 1 to retcode doπ     _message := _message + chr(reply_buffer.message_buffer[count]);πend;ππprocedure log_file(lock_directive:integer; log_filename: string;πlog_timeout:integer; var retcode:integer);πbeginπ    With Regs do beginπ     Ah := $eb;π     Ds := Seg(log_filename);π     Dx := Ofs(log_filename);π     BP := log_timeout;π     end;πmsdos(regs);πretcode := regs.al;πend;ππprocedure release_file(log_filename: string; var retcode:integer);πbeginπ    With Regs do beginπ     Ah := $ec;π     Ds := Seg(log_filename);π     Dx := Ofs(log_filename);π     end;πmsdos(regs);πretcode := regs.al;πend;ππprocedure clear_file(log_filename: string; var retcode:integer);πbeginπ    With Regs do beginπ     Ah := $ed;π     Ds := Seg(log_filename);π     Dx := Ofs(log_filename);π     end;πmsdos(regs);πretcode := regs.al;πend;ππprocedure clear_file_set;πbeginπ regs.Ah := $cf;π msdos(regs);π retcode := regs.al;πend;ππprocedure lock_file_set(lock_timeout:integer; var retcode:integer);πbeginπ regs.ah := $CB;π regs.bp := lock_timeout;π msdos(regs);π retcode := regs.al;πend;ππprocedure release_file_set;πbeginπ regs.ah := $CD;π msdos(regs);πend;ππprocedure open_semaphore( _name:string;π                          _initial_value:shortint;π                          var _open_count:integer;π                          var _handle:longint;π                          var retcode:integer);πvar s_name : array [1..129] of byte;π    count : integer;π    semaphore_handle : array [1..2] of word;πbeginπ  if (_initial_value < 0) or (_initial_value > 127) then _initial_value := 0;π  for count := 1 to 129 do s_name[count] := $00; {zero buffer}π  if length(_name) > 127 then _name := copy(_name,1,127); {limit name length}π  if length(_name) > 0 then for count := 1 to length(_name) do s_name[count+1]π:= ord(_name[count]);π  s_name[1] := length(_name);π  regs.ah := $C5;π  regs.al := $00;π  move(_initial_value, regs.cl, 1);π  regs.ds := seg(s_name);π  regs.dx := ofs(s_name);π  regs.es := 0;π  msdos(regs);π  retcode := regs.al;π  if retcode = 0 then _open_count := regs.bl else _open_count := 0;π  semaphore_handle[1]:=regs.cx;π  semaphore_handle[2]:=regs.dx;π  move(semaphore_handle,_handle,4);πend;ππprocedure close_semaphore(var _handle:longint; var retcode:integer);πvar semaphore_handle : array [1..2] of word;πbeginπ move(_handle,semaphore_handle,4);π regs.ah := $C5;π regs.al := $04;π regs.ds := 0;π regs.es := 0;π regs.cx := semaphore_handle[1];π regs.dx := semaphore_handle[2];π msdos(regs);π retcode := regs.al;  { 00h=successful   FFh=Invalid handle}πend;ππprocedure examine_semaphore(var _handle:longint; var _value:shortint; varπ_count, retcode:integer);πvar semaphore_handle : array [1..2] of word;πbeginπ    move(_handle,semaphore_handle,4);π    regs.ah := $C5;π    regs.al := $01;π    regs.ds := 0;π    regs.es := 0;π    regs.cx := semaphore_handle[1];π    regs.dx := semaphore_handle[2];π    msdos(regs);π    retcode := regs.al; {00h=successful FFh=invalid handle}π    move(regs.cx, _value, 1);π    _count := regs.dl;πend;ππprocedure signal_semaphore(var _handle:longint; var retcode:integer);πvar semaphore_handle : array [1..2] of word;πbeginπ    move(_handle,semaphore_handle,4);π    regs.ah := $C5;π    regs.al := $03;π    regs.ds := 0;π    regs.es := 0;π    regs.cx := semaphore_handle[1];π    regs.dx := semaphore_handle[2];π    msdos(regs);π    retcode := regs.al;π    {00h=successful   01h=overflow value > 127   FFh=invalid handle}πend;ππprocedure wait_on_semaphore(var _handle:longint; _timeout:integer; varπretcode:integer);πvar semaphore_handle : array [1..2] of word;πbeginπ    move(_handle,semaphore_handle,4);π    regs.ah := $C5;π    regs.al := $02;π    regs.ds := 0;π    regs.es := 0;π    regs.bp := _timeout; {units in 1/18 of second,   0 = no wait}π    regs.cx := semaphore_handle[1];π    regs.dx := semaphore_handle[2];π    msdos(regs);π    retcode := regs.al;π    {00h=successful   FEh=timeout failure   FFh=invalid handle}πend;ππprocedure clear_connection(connection_number : integer; var retcode :πinteger);πvar con_num : byte;ππ    request_buffer : recordπ            length : integer;π       subfunction : byte;π           con_num : byte;π               end;ππ      reply_buffer : recordπ            length : integer;π               end;ππbeginπ  with request_buffer do beginπ     length := 4;π     con_num := connection_number;π     subfunction := $D2;π     end;π  reply_buffer.length := 0;π  with regs do beginπ     Ah := $e3;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  msdos(regs);π  retcode := regs.al;πend;πππprocedure get_server_lan_driver_information(var _lan_board_number : integer;π{ This will return info on what }           var _text1,_text2:string;π{ type of network cards are being }         var _network_address : byte4;π{ used in the server. }                     var _host_address : byte6;π                                            var _driver_installed,π                                                _option_number,π                                                _retcode : integer);ππvar      count : integer;π          text : array [1..3] of string;π            x1 : integer;ππ         request_buffer : recordπ                 length : integer;π            subfunction : byte;π              lan_board : byte;π                     end;ππ           reply_buffer : recordπ                 length : integer;π        network_address : byte4;π           host_address : byte6;π   lan_driver_installed : byte;π          option_number : byte;π     configuration_text : array [1..160] of byte;π                     end;πbeginπ with request_buffer do beginπ      length := 2;π      subfunction := $E3;π      lan_board := _lan_board_number; { 0 to 3 }π      end;π with reply_buffer do beginπ      length := 174;π      for count := 1 to 4 do network_address[count] := $0;π      for count := 1 to 6 do host_address[count] := $0;π      lan_driver_installed := 0;π      option_number := 0;π      for count := 1 to 160 do configuration_text[count] := $0;π      end;π  with regs do beginπ     Ah := $E3;π     Ds := Seg(request_buffer);π     Si := Ofs(request_buffer);π     Es := Seg(reply_buffer);π     Di := Ofs(reply_buffer);π     end;π  msdos(regs);π  retcode := regs.al;π  _text1 := '';π  _text2 := '';π  if retcode <> 0 then exit;π  _driver_installed := reply_buffer.lan_driver_installed;π  if reply_buffer.lan_driver_installed = 0 then exit;π  {-- set some values ---}π  for count := 1 to 3 do text[count] := '';π  x1 := 1;π    with reply_buffer do beginπ      _network_address := network_address;π      _host_address := host_address;π      _option_number := option_number;π      for count := 1 to 160 doπ      beginπ      if ((configuration_text[count] = 0) and (x1 <> 3)) then x1 := x1+1;π      if configuration_text[count] <> 0 thenπ         text[x1] := text[x1] + chr(configuration_text[count]);π      end;π    end;π  _text1 := text[1];π  _text2 := text[2];πend;ππend. { end of unit novell }π  3      05-26-9411:03ALL                      R. GILOMEN               Novell IPX functions     SWAG9405            398    ,î   UNIT IPX;π(****************************************************************************)π(*                                                                          *)π(*  PROJEKT        : PASCAL Treiber fuer Novell-NetWare                     *)π(*  MODULE         : IPX.PAS                                                *)π(*  VERSION        : 1.10C                                                  *)π(*  COMPILER       : Turbo Pascal V 6.0                                     *)π(*  DATUM          : 13.06.91                                               *)π(*  AUTOR          : R. Gilomen                                             *)π(*  GEPRUEFT       : R. Gilomen                                             *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG   : Bibliothek mit den IPX-Grunfunktionen. Dieses Modul    *)π(*                   wurde mit IPX Version 2.12 getestet.                   *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  MODIFIKATIONEN :                                                        *)π(*                                                                          *)π(*  Version  1.00A      20.02.91  R. Gilomen    Initial Version             *)π(*  Version  1.10A      28.02.91  R. Gilomen    Neue Funktionen             *)π(*                                              IPX_To_Addr                 *)π(*                                              IPX_From_Addr               *)π(*                                              IPX_Internetwork_Address    *)π(*  Version  1.10B      07.03.91 R. Gilomen     Fehler in Funktion IPX_Done *)π(*                                              behoben. Bei SEND wurde     *)π(*                                              Source.Socket veraendert.   *)π(*  Version  1.10C      13.06.91 R. Gilomen     Defaultwert fuer Parameter  *)π(*                                              STAY_OPEN auf $FF gesetzt.  *)π(*                                                                          *)π(****************************************************************************)πππ(*//////////////////////////////////////////////////////////////////////////*)π                                   INTERFACEπ(*//////////////////////////////////////////////////////////////////////////*)πππ(*==========================================================================*)π(*                         DEKLARATIONEN / DEFINITIONEN                     *)π(*==========================================================================*)ππCONSTππ(* Allgemeine Deklarationen *)ππ         MAX_SOCKETS          = 20;    (* Maximale Anzahl konfigurierte     *)π                                       (* Kommunikationssockel.             *)π         MAX_DATA_SIZE        = 546;   (* Maximale Datenlaenge              *)π         NET_LENGTH           = 4;     (* Laenge Netzwerkadresse            *)π         NODE_LENGTH          = 6;     (* Laenge Knotenadresse              *)π   ππ(* Code Deklarationen *)ππ         SEND                  = $10;π         RECEIVE               = $20;πππ(* Deklaration der Rueckgabewerte *)ππ         SUCCESS               = $00;π         NOT_ENDED             = $10;π         PARAMETER_ERROR       = $20;π         NO_DESTINATION        = $21;π         DEVICE_SW_ERROR       = $30;π         SOCKET_TABLE_FULL     = $31;π         PACKET_BAD            = $32;π         PACKET_UNDELIVERIABLE = $33;π         PACKET_OVERFLOW       = $34;π         DEVICE_HW_ERROR       = $40;πππTYPE   S4Byte          =  ARRAY [1..4]  OF BYTE; (* Datentyp fuer Network   *)π       S6Byte          =  ARRAY [1..6]  OF BYTE; (* Datentyp fuer Node      *)ππ                                                 (* Datentyp fuer Daten     *)π       Data_Packet     = ARRAY [1..MAX_DATA_SIZE] OF CHAR;ππ       SData           = RECORD                  (* Daten und Laenge        *)π                           Data   : Data_Packet;π                           Length : WORD;π                          END;ππ       Network_Address = RECORD                  (* Datentyp fuer NW-Adr.   *)π                           Network     : S4Byte;π                           Node        : S6Byte;π                           Socket      : WORD;π                         END;πππ(*==========================================================================*)π(*                         PROZEDUREN / FUNKTIONEN                          *)π(*==========================================================================*)πππFUNCTION IPX_Setup : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG : Die Routine initialisiert die IPX-Software und deren     *)π(*                 Funktion.                                                *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : -                                                  *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_Open_Socket ( VAR Socket : WORD ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine eroeffnet einen Kommunikationssockel.       *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Nummer des Sockels, der eroeffnet  *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Socket        = Nummer des Sockels, der effektiv   *)π(*                                       geoeffnet wurde.                   *)π(*                                                                          *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_Close_Socket ( Socket : WORD ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine schliesst einen Kommunikationssockel.       *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Nummer des Sockels, der geschlos-  *)π(*                                       sen werden soll.                   *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_Send ( Socket    : WORD;π                    Dest_Addr : Network_Address;π                    Buffer    : SDataπ                  ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine dient zum senden von Daten an eine oder     *)π(*                  mehrere Gegenstationen.                                 *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Sockelnummer, auf der gesendet     *)π(*                                       werden soll.                       *)π(*                       Dest_Addr     = Vollstaendige Netwerkadresse der   *)π(*                                       Gegenstation(en).                  *)π(*                       Buffer        = Daten die gesendet werden und      *)π(*                                       dessen Laenge.                     *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_Receive ( Socket : WORD ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine dient zum Empfangen von Daten einer Gegen-  *)π(*                  station. Die Daten koennen, wenn das Kommando beendet   *)π(*                  ist, mit der Funktion IPX_Done vom Netzwerk abgeholt    *)π(*                  werden.                                                 *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Sockelnummer, auf der empfangen    *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_Done ( Socket          : WORD;π                    Code            : BYTE;π                    VAR Source_Addr : Network_Address;π                    VAR Buffer      : SDataπ                  ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Funktion liefert den Status einer vorher abgesetz-  *)π(*                  ten Routine. Zurueckgegeben wird, ob die Routine schon  *)π(*                  beendet ist oder nicht sowie eventuelle Daten.          *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Sockelnummer, auf der die Funktion *)π(*                                       ausgefuehrt werden soll.           *)π(*                       Code          = Routine, deren Status ueberprueft  *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Source_Addr   = Vollstaendige Netzwerkadresse der  *)π(*                                       Gegenstation, von der Daten einge- *)π(*                                       troffen sind.                      *)π(*                       Buffer        = Buffer, in dem eventuelle Daten    *)π(*                                       abgelegt werden koennen.           *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_Internetwork_Address ( VAR Network : S4Byte;π                                    VAR Node    : S6Byteπ                                  ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Funktion liefert die Internetzwerkadresse der       *)π(*                  jeweiligen Station.                                     *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  OUT: Network       = Netzwerkadresse                    *)π(*                       Node          = Knotenadresse                      *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_To_Addr ( Network     : String;π                       Node        : String;π                       Socket      : String;π                       VAR Addr    : Network_Addressπ                     ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG : Die Routine konvertiert die Eingabestrings in die Daten- *)π(*                 struktur Network_Address.                                *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Network       = Netzwerkadresse die konvertiert    *)π(*                                       werden soll.                       *)π(*                       Node          = Knotenadresse die konvertiert      *)π(*                                       werden soll.                       *)π(*                       Socket        = Sockelnummer die konvertiert       *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Addr          = Konvertierte vollsaendige Netz-    *)π(*                                       werkadresse.                       *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππππFUNCTION IPX_From_Addr ( Addr            : Network_Address;π                         VAR Network     : String;π                         VAR Node        : String;π                         VAR Socket      : Stringπ                       ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG : Die Routine konvertiert die vollstaendige Netzwerk-      *)π(*                 adresse in String's.                                     *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Addr          = Vollstaendige Netzwerkadresse      *)π(*                                                                          *)π(*                  OUT: Network       = Netzwerkadresse die konvertiert    *)π(*                                       wurde.                             *)π(*                       Node          = Knotenadresse die konvertiert      *)π(*                                       wurde.                             *)π(*                       Socket        = Sockelnummer die konvertiert       *)π(*                                       wurde.                             *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)πππππ(*//////////////////////////////////////////////////////////////////////////*)π                                 IMPLEMENTATIONπ(*//////////////////////////////////////////////////////////////////////////*)πππ(*==========================================================================*)π(*                                UNITS IMPORT                              *)π(*==========================================================================*)ππUSES     Dos;ππ(*==========================================================================*)π(*                         DEKLARATIONEN / DEFINITIONEN                     *)π(*==========================================================================*)πππCONSTππ(* Allgemeine Definitionen *)ππ         HEADER       = 30;            (* Groesse IPX-Header                *)π         PACKET_SIZE  = 576;           (* IPX-Paket groesse                 *)πππ(* Definitionen der IPX-Funktionen *)ππ         IPX_TST      = $7A00;         (* Vorbereiten fuer IPX Test         *)π         MUX_INTR     = $2F;           (* Multiplex Interrupt               *)π         OPEN_SOCKET  = $0000;         (* Oeffnet einen Sockel              *)π         CLOSE_SOCKET = $0001;         (* Schliesst einen Sockel            *)π         GET_TARGET   = $0002;         (* Pruefe Gegenstation               *)π         DO_SEND      = $0003;         (* Sendet ein Paket                  *)π         DO_RECEIVE   = $0004;         (* Empfaengt Pakete                  *)π         GET_ADDR     = $0009;         (* Bestimmt Internetzwerkadresse     *)πππ(* Definitionen der IPX-Parameter *)ππ         STAY_OPEN    = $FF;           (* $00 : Sockel bleibt geoeffnet,    *)π                                       (* bis er explizit geschlossen wird  *)π                                       (* oder das Programm terminiert.     *)π                                       (* $FF : Sockel bleibt geoeffnet,    *)π                                       (* bis er explizit geschlossen wird. *)π                                       (* Wird benoetigt fuer TSR-Programme.*)ππ(* Definitionen der IPX-Rueckgabewerte *)ππ         IPX_LOADED   = $FF;           (* IPX ist geladen                   *)π         OPENED       = $00;           (* Sockel erfolgreich geoeffnet      *)π         ALREADY_OPEN = $FF;           (* Sockel ist bereits goeffnet       *)π         TABLE_FULL   = $FE;           (* Sockel Tabelle ist voll           *)π         EXIST        = $00;           (* Weg zu Gegenstation existiert     *)π         NO_SOCKET    = $FF;           (* Sockel existiert nicht            *)π         SEND_OK      = $00;           (* Senden war erfolgreich            *)π         SOCKET_ERROR = $FC;           (* Sockel existiert nicht mehr       *)π         SIZE_ERROR   = $FD;           (* Paketgroesse nicht korrekt        *)π         UNDELIV      = $FE;           (* Paket nicht ausgeliefert          *)π         OVERFLOW     = $FD;           (* Buffer zu klein                   *)π         HW_ERROR     = $FF;           (* Hardware defekt                   *)π         REC_OK       = $00;           (* Paket erfolgreich empfangen       *)πππ(* Definition der ECB-Parameter *)ππ         FINISHED     = $00;           (* Routine beendet                   *)π         FRAG_COUNT   = 1;             (* Anzahl Fragmente                  *)π         UNKNOWN      = 0;             (* Unbekannter Paket Typ             *)ππ(* Deklarationen *)ππTYPE     S12Byte      = ARRAY [1..12] OF BYTE;   (* Interner Datentyp       *)ππ         IPX_Packet   = RECORD         (* IPX-Paket Struktur                *)π                          CheckSum         : WORD;π                          Length           : WORD;π                          TransportControl : BYTE;π                          PacketType       : BYTE;π                          Destination      : Network_Address;π                          Source           : Network_Address;π                          IPX_Data         : Data_Packet;π                        END;ππ         ECB_Fragment = RECORD         (* Fragment der ECB Struktur         *)π                          Address : ^IPX_Packet;π                          Size    : WORD;π                        END;ππ         ECB = RECORD                  (* ECB Datenstruktur                 *)π                Link_Adress        : S4Byte;π                ESR_Address        : ^BYTE;π                InUseFlag          : BYTE;π                CompletionCode     : BYTE;π                SocketNumber       : WORD;π                IPX_Workspace      : S4Byte;π                DriverWorkspace    : S12Byte;π                ImmediateAddress   : S6Byte;π                FragmentCount      : WORD;π                FragDescr          : ECB_Fragment;π               END;πππ         Int_Addr = RECORD             (* Datenstruktur Internetzwerkadr.   *)π                      Network : S4Byte;π                      Node    : S6Byte;π                    END;πππVAR      IPX_Location : ARRAY [1..2] OF WORD;    (* Adresse von IPX         *)ππ                                                 (* Array in dem die ECB's  *)π                                                 (* verwaltet werden.       *)π         ECB_Table    : ARRAY [1..MAX_SOCKETS] OF ^ECB;πππ(*==========================================================================*)π(*                         PROZEDUREN / FUNKTIONEN                          *)π(*==========================================================================*)πππPROCEDURE IPX_Call ( VAR Regs : Registers );π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Diese Prozedur setzt die in Regs spezifizierten         *)π(*                  Register des Prozessors. Anschliessend wird ein IPX-    *)π(*                  Call ausgefuehrt und die Register wieder ausgelesen.    *)π(*                  Es werden nicht alle Register der Datenstruktur         *)π(*                  Regs uebernommen!                                       *)π(*                                                                          *)π(*  PARAMETER    :  IN : Regs          = Register, die gesetzt werden       *)π(*                                       sollen.                            *)π(*                                                                          *)π(*                  OUT: Regs          = Register, die vom IPX gesetzt      *)π(*                                       wurden (Return values).            *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      Temp_AX, Temp_BX, Temp_CX, Temp_DX,π         Temp_ES, Temp_SI, Temp_DI               : WORD;ππBEGINπ Temp_AX := Regs.AX;π Temp_BX := Regs.BX;π Temp_CX := Regs.CX;π Temp_DX := Regs.DX;π Temp_SI := Regs.SI;π Temp_ES := Regs.ES;π Temp_DI := Regs.DI;π ASMπ  PUSH BP                              (* Register sichern                  *)π  PUSH SPπ  PUSH SSπ  PUSH DSπ  PUSH AXπ  PUSH BXπ  PUSH CXπ  PUSH DXπ  PUSH SIπ  PUSH ESπ  PUSH DIπ  MOV AX, Temp_AX                      (* Register setzen                   *)π  MOV BX, Temp_BXπ  MOV CX, Temp_CXπ  MOV DX, Temp_DXπ  MOV SI, Temp_SIπ  MOV ES, Temp_ESπ  MOV DI, Temp_DIπ  CALL DWORD PTR IPX_Location          (* IPX aufrufen                      *)π  MOV Temp_AX, AX                      (* Register auslesen                 *)π  MOV Temp_BX, BXπ  MOV Temp_CX, CXπ  MOV Temp_DX, DXπ  MOV Temp_SI, SIπ  MOV Temp_ES, ESπ  MOV Temp_DI, DIπ  POP DIπ  POP ES                               (* Gesicherte Register wieder        *)π  POP SI                               (* zuruecksetzen.                    *)π  POP DXπ  POP CXπ  POP BXπ  POP AXπ  POP DS                               π  POP SS                               π  POP SPπ  POP BPπ END;ππ Regs.AX := Temp_AX;π Regs.BX := Temp_BX;π Regs.CX := Temp_CX;π Regs.DX := Temp_DX;π Regs.SI := Temp_SI;π Regs.ES := Temp_ES;π Regs.DI := Temp_DI;πEND;ππππFUNCTION IPX_Setup : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG : Die Routine initialisiert die IPX-Software und deren     *)π(*                 Funktion.                                                *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : -                                                  *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      i        : INTEGER;           (* Laufvariable                      *)π         Temp_Reg : Registers;         (* Temporaere Register fuer Int.     *)πππBEGINπ  Temp_Reg.AX := IPX_TST;              (* Test ob IPX geladen.              *)π  Intr (MUX_INTR,Temp_Reg);π  IF (Temp_Reg.AL <> IPX_LOADED) THENπ  BEGINπ    IPX_Setup := DEVICE_SW_ERROR;      (* IPX nicht geladen                 *)π    EXIT;π  END;π  Temp_Reg.AX := Temp_Reg.ES;π  IPX_Location[1] := Temp_Reg.DI;      (* Adresse von IPX sichern           *)π  IPX_Location[2] := Temp_Reg.AX;ππ  FOR i := 1 TO MAX_SOCKETS DO         (* Array fuer ECB init.              *)π    ECB_Table[i] := NIL;ππ  IPX_Setup := SUCCESS;                (* Initialisierung erfolgreich       *)πEND;ππππFUNCTION IPX_Open_Socket ( VAR Socket : WORD ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine eroeffnet einen Kommunikationssockel.       *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Nummer des Sockels, der eroeffnet  *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Socket        = Nummer des Sockels, der effektiv   *)π(*                                       geoeffnet wurde.                   *)π(*                                                                          *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      i        : INTEGER;           (* Laufvariable                      *)π         Index    : INTEGER;           (* Index auf ECB_Table               *)ππ         Temp_Reg : Registers;         (* Temporaere Register fuer IPX-Call *)πππBEGINπ  Socket := Swap(Socket);              (* In Motorola Format konvertieren   *)ππ  FOR i := 1 TO MAX_SOCKETS DO         (* Pruefen, ob Sockel existiert      *)π    IF ECB_Table[i] <> NIL THENπ      IF Socket = ECB_Table[i]^.SocketNumber THENπ      BEGINπ        IPX_Open_Socket := PARAMETER_ERROR;π        EXIT;π      END;ππ  Index := 1;π  WHILE (ECB_Table[Index] <> NIL) DO   (* Pruefen, ob alle Sockel belegt    *)π  BEGIN                                (* falls es noch freie ECB hat,      *)π    IF Index >= MAX_SOCKETS THEN       (* steht Index auf einem solchen.    *)π    BEGINπ      IPX_Open_Socket := SOCKET_TABLE_FULL;π      EXIT;π    END;π    Index := Index + 1;π  END;ππ  Temp_Reg.BX := OPEN_SOCKET;          (* Register fuer Call vorbereiten    *)π  Temp_Reg.AL := STAY_OPEN;π  Temp_Reg.DX := Socket;ππ  IPX_Call (Temp_Reg);ππ  Socket := Temp_Reg.DX;               (* Register auslesen                 *)ππ  IF Temp_Reg.AL <> OPENED THEN        (* IPX nicht i.O.                    *)π  BEGINπ    IPX_Open_Socket := DEVICE_SW_ERROR;π    EXIT;π  END;ππ  NEW (ECB_Table[Index]);              (* Vollstaendiger ECB erzeugen       *)π  NEW (ECB_Table[Index]^.FragDescr.Address);π  ECB_Table[Index]^.SocketNumber := Socket;ππ  Socket := Swap(Socket);              (* Zurueck in INTEL Format konv.     *)π  IPX_Open_Socket := SUCCESS;ππEND;ππππFUNCTION IPX_Close_Socket ( Socket : WORD ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine schliesset einen Kommunikationssockel.      *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Nummer des Sockels, der geschlos-  *)π(*                                       sen werden soll.                   *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      Index    : INTEGER;           (* Index auf ECB_Table               *)ππ         Temp_Reg : Registers;         (* Temporaere Register fuer IPX-Call *)πππBEGINπ  Socket := Swap(Socket);              (* In Motorola Format konvertieren   *)ππ  Index := 1;                          (* Sockel suchen                     *)π  WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DOπ  BEGIN                               π    IF Index >= MAX_SOCKETS THENπ    BEGINπ      IPX_Close_Socket := PARAMETER_ERROR;       (* Sockel existiert nicht  *)π      EXIT;π    END;π    Index := Index + 1;π  END;ππ  Temp_Reg.BX := CLOSE_SOCKET;         (* Register fuer Call vorbereiten    *)π  Temp_Reg.DX := Socket;ππ  IPX_Call (Temp_Reg);ππ                                       (* Allozierter Speicher freigeben    *)π  DISPOSE (ECB_Table[Index]^.FragDescr.Address);π  ECB_Table[Index]^.FragDescr.Address := NIL;π  DISPOSE (ECB_Table[Index]);π  ECB_Table[Index] := NIL;π ππ  IPX_Close_Socket := SUCCESS;ππEND;ππππFUNCTION IPX_Send ( Socket    : WORD;π                    Dest_Addr : Network_Address;π                    Buffer    : SDataπ                  ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine dient zum senden von Daten an eine oder     *)π(*                  mehrere Gegenstation(en).                               *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Sockelnummer, auf der gesendet     *)π(*                                       werden soll.                       *)π(*                       Dest_Addr     = Vollstaendige Netwerkadresse der   *)π(*                                       Gegenstation(en).                  *)π(*                       Buffer        = Daten die gesendet werden und      *)π(*                                       dessen Laenge.                     *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      i         : INTEGER;          (* Laufvariable                      *)π         Index     : INTEGER;          (* Index auf ECB_Table               *)ππ         Temp_Reg  : Registers;        (* Temporaere Register fuer IPX-Call *)ππ         Temp_Imm_Addr : S6Byte;       (* Temporaere ImmdediateAddress      *)ππ         Temp_Addr : S12Byte;          (* Temporaere Internetworkadresse    *)πππBEGINπ  Socket := Swap(Socket);              (* In Motorola Format konvertieren   *)π  Dest_Addr.Socket := Swap(Dest_Addr.Socket);ππ  Index := 1;                          (* Sockel suchen                     *)π  WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DOπ  BEGINπ    IF Index >= MAX_SOCKETS THENπ    BEGINπ      IPX_Send := PARAMETER_ERROR;     (* Sockel existiert nicht            *)π      EXIT;π    END;π    Index := Index + 1;π  END;ππ  IF Buffer.Length > MAX_DATA_SIZE THEN     (* Laenge der Daten pruefen     *)π  BEGINπ    IPX_Send := PARAMETER_ERROR;π    EXIT;π  END;ππ  WITH Dest_Addr DO                    (* Pruefe ob Gegenstation erreichbar *)π  BEGINπ    FOR i := 1 TO NET_LENGTH DO        (* Internetzwerkadresse zusammenst.  *)π      Temp_Addr[i] := Network[i];π    FOR i := 1 TO NODE_LENGTH DOπ      Temp_Addr[i + NET_LENGTH] := Node[i];π    Temp_Addr[11] := Lo(Socket);       (* Low-Byte                          *)π    Temp_Addr[12] := HI(Socket);       (* High-Byte                         *)π  END;ππ  Temp_Reg.ES := Seg(Temp_Addr);       (* Register fuer Call vorbereiten    *)π  Temp_Reg.SI := Ofs(Temp_Addr);ππ  Temp_Reg.DI := Ofs(Temp_Imm_Addr);π  Temp_Reg.BX := GET_TARGET;ππ  IPX_Call (Temp_Reg);ππ  ECB_Table[Index]^.ImmediateAddress := Temp_Imm_Addr;ππ  IF Temp_Reg.AL <> EXIST THENπ  BEGINπ    IPX_Send := NO_DESTINATION;        (* Weg nicht verfuegbar              *)π    EXIT;π  END;ππ  WITH ECB_Table[Index]^ DO            (* ECB mit Parametern fuellen        *)π  BEGINπ    ESR_Address := NIL;π    SocketNumber := Socket;π    InUseFlag := FINISHED;π    FragmentCount := FRAG_COUNT;π    WITH FragDescr.Address^ DO         (* IPX-Header vorbereiten            *)π    BEGINπ      PacketType := UNKNOWN;π      WITH Destination DOπ      BEGINπ        Network := Dest_Addr.Network;π        Node := Dest_Addr.Node;π        Socket := Dest_Addr.Socket;π      END;π      IPX_Data := Buffer.Data;π    END;π    FragDescr.Size := Buffer.Length + 30;π  END;ππ  Temp_Reg.ES := Seg(ECB_Table[Index]^);  (* Register fuer Call vorbereiten *)π  Temp_Reg.SI := Ofs(ECB_Table[Index]^);π  Temp_Reg.BX := DO_SEND;ππ  IPX_Call (Temp_Reg);ππ  IPX_Send := SUCCESS;ππEND;ππππFUNCTION IPX_Receive ( Socket : WORD ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Routine dient zum Empfangen von Daten einer Gegen-  *)π(*                  station. Die Daten koennen, wenn das Kommando beendet   *)π(*                  ist, mit der Funktion IPX_Done vom Netzwerk abgeholt    *)π(*                  werden.                                                 *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Sockelnummer, auf der empfangen    *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      Index     : INTEGER;          (* Index auf ECB                     *)π         i         : INTEGER;          (* Laufvariable                      *)ππ         Temp_Reg  : Registers;        (* Temporaere Register fuer IPX-Call *)πππBEGINπ  Socket := Swap(Socket);              (* In Motorola Format konvertieren   *)ππ  Index := 1;                          (* Sockel suchen                     *)π  WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DOπ  BEGINπ    IF Index >= MAX_SOCKETS THENπ    BEGINπ      IPX_Receive := PARAMETER_ERROR;  (* Sockel existiert nicht            *)π      EXIT;π    END;π    Index := Index + 1;π  END;ππ  WITH ECB_Table[Index]^ DO            (* ECB mit Parametern fuellen        *)π  BEGINπ    ESR_Address := NIL;π    FragmentCount := FRAG_COUNT;π    FragDescr.Size := PACKET_SIZE;π    InUseFlag := FINISHED;π  END;ππ  Temp_Reg.ES := Seg(ECB_Table[Index]^);    (* Register vorbereiten         *)π  Temp_Reg.SI := Ofs(ECB_Table[Index]^);π  Temp_Reg.BX := DO_RECEIVE;ππ  IPX_Call (Temp_Reg);ππ  IF Temp_Reg.AL = NO_SOCKET THENπ  BEGINπ    IPX_Receive := DEVICE_SW_ERROR;π    EXIT;π  END;ππ  IPX_Receive := SUCCESS;ππEND;πππππFUNCTION IPX_Done ( Socket          : WORD;π                    Code            : BYTE;π                    VAR Source_Addr : Network_Address;π                    VAR Buffer      : SDataπ                  ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Funktion liefert den Status einer vorher abgesetz-  *)π(*                  ten Routine. Zurueckgegeben wird, ob die Routine schon  *)π(*                  beendet ist oder nicht sowie eventuelle Daten.          *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Socket        = Sockelnummer, auf der die Funktion *)π(*                                       ausgefuehrt werden soll.           *)π(*                       Code          = Routine, deren Status ueberprueft  *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Source_Addr   = Vollstaendige Netzwerkadresse der  *)π(*                                       Gegenstation, von der Daten einge- *)π(*                                       troffen sind.                      *)π(*                       Buffer        = Buffer, in dem eventuelle Daten    *)π(*                                       abgelegt werden koennen.           *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      i         : INTEGER;          (* Laufvariable                      *)π         Index     : INTEGER;          (* Index auf ECB_Table               *)ππ         Temp_Reg  : Registers;        (* Temporaere Register fuer IPX-Call *)πππBEGINπ  Socket := Swap(Socket);              (* In Motorola Format konvertieren   *)ππ  Index := 1;                          (* Sockel suchen                     *)π  WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DOπ  BEGINπ    IF Index >= MAX_SOCKETS THENπ    BEGINπ      IPX_Done := PARAMETER_ERROR;     (* Sockel existiert nicht            *)π      EXIT;π    END;π    Index := Index + 1;π  END;π                                       (* Test ob Funktion beendet          *)π  IF ECB_Table[Index]^.InUseFlag <> FINISHED THENπ  BEGINπ     IPX_Done := NOT_ENDED;π     EXIT;π  END;ππ  CASE Code OFπ    SEND :π    BEGIN                              (* Send Completion Code auswerten    *)π      CASE ECB_Table[Index]^.CompletionCode OFπ        SEND_OK      : ;π        SOCKET_ERROR : BEGINπ                         IPX_Done := DEVICE_SW_ERROR;π                         EXIT;π                       END;π        SIZE_ERROR   : BEGINπ                         IPX_Done := PACKET_BAD;π                         EXIT;π                       END;π        UNDELIV      : BEGINπ                         IPX_Done := PACKET_UNDELIVERIABLE;π                         EXIT;π                       END;π        HW_ERROR     : BEGINπ                         IPX_Done := DEVICE_HW_ERROR;π                         EXIT;π                       ENDπ        ELSE           BEGINπ                         IPX_Done := DEVICE_SW_ERROR;π                         EXIT;π                       END;π      END;π    END;π    RECEIVE :π    BEGIN                             (* Receive Completion Code auswerten  *)π      CASE ECB_Table[Index]^.CompletionCode OFπ        REC_OK : BEGIN                 (* Daten in Benutzerbuffer kopieren  *)π                   WITH ECB_Table[Index]^.FragDescr DOπ                   BEGINπ                     Buffer.Data := Address^.IPX_Data;π                     Buffer.Length := Swap(Address^.Length) - HEADER;π                   END;π                                       (* Netzwerkadresse umkopieren        *)π                   WITH ECB_Table[Index]^.FragDescr.Address^.Source DOπ                   BEGINπ                     Source_Addr.Network := Network;π                     Source_Addr.Node := Node;π                     Source_Addr.Socket := Swap(Socket);π                   END;π                 END;π        SOCKET_ERROR : BEGINπ                         IPX_Done := DEVICE_SW_ERROR;π                         EXIT;π                       END;π        OVERFLOW     : BEGINπ                         IPX_Done := PACKET_OVERFLOW;π                         EXIT;π                       END;π        NO_SOCKET    : BEGINπ                         IPX_Done := DEVICE_SW_ERROR;π                         EXIT;π                       ENDπ        ELSE           BEGINπ                         IPX_Done := DEVICE_SW_ERROR;π                         EXIT;π                       END;π      END;π    ENDπ    ELSE  BEGINπ            IPX_Done := PARAMETER_ERROR;π          EXIT;π    END;ππ  END;ππ  IPX_Done := SUCCESS;ππEND;ππππFUNCTION IPX_Internetwork_Address ( VAR Network : S4Byte;π                                    VAR Node    : S6Byteπ                                  ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG :  Die Funktion liefert die Internetzwerkadresse der       *)π(*                  jeweiligen Station.                                     *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  OUT: Network       = Netzwerkadresse                    *)π(*                       Node          = Knotenadresse                      *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      Temp_Reg     : Registers;     (* Temporaere Register fuer IPX-Call *)ππ         Reply_Buffer : Int_Addr;      (* Temporaerer Buffer fuer Adressen  *)ππBEGINππ  Temp_Reg.ES := Seg(Reply_Buffer);    (* Register vorbereiten              *)π  Temp_Reg.SI := Ofs(Reply_Buffer);π  Temp_Reg.BX := GET_ADDR;ππ  IPX_Call (Temp_Reg);ππ  Network := Reply_Buffer.Network;     (* Daten umkopieren                  *)π  Node := Reply_Buffer.Node;ππ  IPX_Internetwork_Address := SUCCESS;ππEND;ππππFUNCTION IPX_To_Addr ( Network     : String;π                       Node        : String;π                       Socket      : String;π                       VAR Addr    : Network_Addressπ                     ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG : Die Routine konvertiert die Eingabestrings in die Daten- *)π(*                 struktur Network_Address.                                *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Network       = Netzwerkadresse die konvertiert    *)π(*                                       werden soll.                       *)π(*                       Node          = Knotenadresse die konvertiert      *)π(*                                       werden soll.                       *)π(*                       Socket        = Sockelnummer die konvertiert       *)π(*                                       werden soll.                       *)π(*                                                                          *)π(*                  OUT: Addr          = Konvertierte vollsaendige Netz-    *)π(*                                       werkadresse.                       *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      i,n,Code  : INTEGER;π         c         : CHAR;π         Temp      : BYTE;ππBEGINππ  (* Pruefe Netzwerk und Node Laenge *)π  IF (ORD(Network[0]) <> (2 * NET_LENGTH)) ORπ     (ORD(Node[0]) <> (2 * NODE_LENGTH)) THENπ  BEGINπ    IPX_To_Addr := PARAMETER_ERROR;π    EXIT;π  END;ππ  (* Netzwerkadresse konvertieren *)π  i := 1;π  n := 1;π  WHILE ( i <= (2 * NET_LENGTH)) DOπ  BEGINπ    c := UPCASE(Network[i]);π    CASE c OFπ      'A'..'F': Addr.Network[n] := ORD(c) - 55;π      '0'..'9': Addr.Network[n] := ORD(c) - 48π    ELSE        BEGINπ                  IPX_To_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    Addr.Network[n] := Addr.Network[n] SHL 4;π    c := UPCASE(Network[i + 1]);π    CASE c OFπ      'A'..'F': Temp := ORD(c) - 55;π      '0'..'9': Temp := ORD(c) - 48;π    ELSE        BEGINπ                  IPX_To_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    Addr.Network[n] := Addr.Network[n] + Temp;π    i := i + 2;π    n := n + 1;π  END;πππ  (* Node-Adresse konvertieren *)π  i := 1;π  n := 1;π  WHILE ( i <= (2 * NODE_LENGTH)) DOπ  BEGINπ    c := UPCASE(Node[i]);π    CASE c OFπ      'A'..'F': Addr.Node[n] := ORD(c) - 55;π      '0'..'9': Addr.Node[n] := ORD(c) - 48;π    ELSE        BEGINπ                  IPX_To_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    Addr.Node[n] := Addr.Node[n] SHL 4;π    c := UPCASE(Node[i + 1]);π    CASE c OFπ      'A'..'F': Temp := ORD(c) - 55;π      '0'..'9': Temp := ORD(c) - 48;π    ELSE        BEGINπ                  IPX_To_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    Addr.Node[n] := Addr.Node[n] + Temp;π    i := i + 2;π    n := n + 1;π  END;ππ  (* Sockelnummer konvertieren *)π  VAL (Socket,Addr.Socket,Code);π  IF Code <> 0 THENπ  BEGINπ    IPX_To_Addr := PARAMETER_ERROR;π    EXIT;π  END;ππ  IPX_To_Addr := SUCCESS;ππEND;ππππFUNCTION IPX_From_Addr ( Addr            : Network_Address;π                         VAR Network     : String;π                         VAR Node        : String;π                         VAR Socket      : Stringπ                       ) : BYTE;π(*--------------------------------------------------------------------------*)π(*                                                                          *)π(*  BESCHREIBUNG : Die Routine konvertiert die vollstaendige Netzwerk-      *)π(*                 adresse in String's.                                     *)π(*                                                                          *)π(*                                                                          *)π(*  PARAMETER    :  IN : Addr          = Vollstaendige Netzwerkadresse      *)π(*                                                                          *)π(*                  OUT: Network       = Netzwerkadresse die konvertiert    *)π(*                                       wurde.                             *)π(*                       Node          = Knotenadresse die konvertiert      *)π(*                                       wurde.                             *)π(*                       Socket        = Sockelnummer die konvertiert       *)π(*                                       wurde.                             *)π(*                       Rueckgabewert = Fehlercode                         *)π(*                                                                          *)π(*--------------------------------------------------------------------------*)ππVAR      i,n,Code      : INTEGER;π         c             : CHAR;π         TempHi,TempLo : BYTE;ππBEGINππ  (* Netzwerkadresse konvertieren *)π  i := 1;π  n := 1;π  WHILE ( i <= (2 * NET_LENGTH)) DOπ  BEGINπ    TempHi := Addr.Network[n] DIV 16;  (* Hi-Nibble                         *)π    CASE TempHi OFπ      10..15  : Network[i] := CHR(TempHi + 55);π      0..9    : Network[i] := CHR(TempHi + 48)π    ELSE        BEGINπ                  IPX_From_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    i := i + 1;π    TempLo := Addr.Network[n] MOD 16;  (* Lo-Nibble                         *)π    CASE TempLo OFπ      10..15  : Network[i] := CHR(TempLo + 55);π      0..9    : Network[i] := CHR(TempLo + 48)π    ELSE        BEGINπ                  IPX_From_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    i := i + 1;π    n := n + 1;π  END;π  Network[0] := CHR(i);               (* Laenge Netzwerkadresse fuer String *)πππ  (* Node-Adresse konvertieren *)π  i := 1;π  n := 1;π  WHILE ( i <= (2 * NODE_LENGTH)) DOπ  BEGINπ    TempHi := Addr.Node[n] DIV 16;     (* Hi-Nibble                         *)π    CASE TempHi OFπ      10..15  : Node[i] := CHR(TempHi + 55);π      0..9    : Node[i] := CHR(TempHi + 48)π    ELSE        BEGINπ                  IPX_From_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    i := i + 1;π    TempLo := Addr.Node[n] MOD 16;     (* Lo-Nibble                         *)π    CASE TempLo OFπ      10..15  : Node[i] := CHR(TempLo + 55);π      0..9    : Node[i] := CHR(TempLo + 48)π    ELSE        BEGINπ                  IPX_From_Addr := PARAMETER_ERROR;π                  EXIT;π                END;π    END;π    i := i + 1;π    n := n + 1;π  END;π  Node[0] := CHR(i - 1);              (* Laenge Knotenadr. fuer String     *)πππ  (* Sockelnummer konvertieren *)π  STR (Addr.Socket,Socket);ππ  IPX_From_Addr := SUCCESS;πEND;ππEND.